﻿using System;
using System.Collections.Generic;

namespace FrameOperateSync
{
    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
    public sealed class FrameRenderAttribute : Attribute
    {
        public int OperateId { get; private set; }
        public Type RenderType { get; private set; }
        public string Desc { get; private set; }

        public FrameRenderAttribute(int operateId, Type renderType, string desc)
        {
            this.OperateId = operateId;
            this.RenderType = renderType;
            this.Desc = desc;
        }
    }

    public static class FrameSyncCenter
    {
        private static Dictionary<int, FrameRenderHander> renderHandlerDic = new Dictionary<int, FrameRenderHander>();
        private static Dictionary<Type, int> renderOperateDic = new Dictionary<Type, int>();
        private static Dictionary<int, Type> operateRenderDic = new Dictionary<int, Type>();
        private static Dictionary<int, string> renderDescDic = new Dictionary<int, string>();

        public static void RegistRenderHander(FrameRenderHander handler)
        {
            var attr = (FrameRenderAttribute)Attribute.GetCustomAttribute(handler.Method, typeof(FrameRenderAttribute), false);
            if (attr == null)
                throw new Exception($"RegistRenderHander invalid,{handler.GetType()} doesnot have a FrameRenderAttribute");
            if (renderHandlerDic.ContainsKey(attr.OperateId))
                throw new Exception($"RegistRenderHander invalid,repeate regist {attr.OperateId}");
            renderHandlerDic.Add(attr.OperateId, handler);
            renderOperateDic.Add(attr.RenderType, attr.OperateId);
            operateRenderDic.Add(attr.OperateId, attr.RenderType);
            renderDescDic.Add(attr.OperateId, attr.Desc);
        }

        public static void UnRegistRenderHander(FrameRenderHander handler)
        {
            var attr = (FrameRenderAttribute)Attribute.GetCustomAttribute(handler.GetType(), typeof(FrameRenderAttribute), false);
            if (attr == null)
                throw new Exception($"RegistRenderHander invalid,{handler.GetType()} doesnot have a FrameRenderAttribute");
            if (!renderHandlerDic.ContainsKey(attr.OperateId))
                throw new Exception($"UnRegistRenderHander invalid,doesnot have {attr.OperateId}");
            renderHandlerDic.Remove(attr.OperateId);
            renderOperateDic.Remove(attr.RenderType);
            operateRenderDic.Remove(attr.OperateId);
            renderDescDic.Remove(attr.OperateId);
        }

        internal static int GetOperateId(IRenderData renderData)
        {
            if (renderOperateDic.TryGetValue(renderData.GetType(), out var id))
                return id;
            throw new Exception($"not found renderType :{renderData.GetType()}");
        }

        internal static Type GetRenderType(int code)
        {
            if (operateRenderDic.TryGetValue(code, out var type))
                return type;
            throw new Exception($"not found renderType :{code}");
        }

        internal static void OnRender(int playerId, int logicCode, int keyFrameIndex, int frameIndex, IRenderData operateData)
        {
            if(renderHandlerDic.TryGetValue(logicCode,out var render))
            {
                render.Invoke(playerId, keyFrameIndex, frameIndex, operateData);
            }
        }
    }
}
